;(function () {
  //在内置工具类型中，访问性修饰工具类型包括以下三位(原理里面)：

  interface IUser1 {
    name: string
    age: number
    gender: number
  }
  type IUser2 = Partial<IUser1>

  /*原理 */
  // type Pratial<T> = {
  //   [P in keyof T]?: T[P]
  // }
  /* ------------------------- */
  interface IUser3 {
    name: string
    age?: number
    gender?: number
  }
  type IUser4 = Required<IUser3>
  /*原理 */
  // type Required<T> = {
  //   [P in keyof T]-?: T[P]
  // }
  /* ----------------------- */
  interface IUser5 {
    name: string
    age: number
    gender: number
  }
  type ReadyIUser5 = Readonly<IUser5>
  /* 原理:Readonly 的作用是将某个类型所有属性变为只读属性，也就意味着这些属性不能被重新赋值。 */
  // type Readonly<T> = {
  //   readonly [p in keyof T]: T[p]
  // }

  /* --------------------- */
  // --如果你觉得不好记，其实 Partial 也可以使用 +? 来显式的表示添加可选标记：
  // type Partial<T> = {
  //   [p in keyof T]+?: T[p]
  // }

  //--需要注意的是，可选标记不等于修改此属性类型为 原类型 | undefined ，如以下的接口结构：
  interface Foo {
    optional: string | undefined
    required: string
  }
  //--如果你声明一个对象去实现这个接口，它仍然会要求你提供 optional 属性：
  //// 类型 "{ required: string; }" 中缺少属性 "optional"，但类型 "Foo" 中需要该属性。
  // const foo1: Foo = {
  //   required: '1'
  //   // optional: undefined
  // }
  const foo2: Foo = {
    required: '1',
    optional: '1'
  }

  interface Foo1 {
    optional: never
    required: string
  }

  // const foo3: Foo1 = {
  //   optional: '1',
  //   required: '1'
  // }
  //没法为这个属性声明值了，毕竟除本身以外没有类型可以赋值给 never 类型。

  //--- 而类似 +?，Readonly 中也可以使用 +readonly：
  // type Readonly<T> = {
  //   +readonly [p in keyof T]: T[p]
  // }

  interface IUser6 {
    readonly name: string
    readonly age: number
    readonly gender: number
  }

  //--虽然 TypeScript 中并没有提供它的另一半，但参考 Required 其实我们很容易想到这么实现一个工具类型 Mutable，来将属性中的 readonly 修饰移除：
  type Mutable<T> = {
    -readonly [p in keyof T]: T[p]
  }
  type IUser6_mutable = Mutable<IUser6>

  /*
 现在我们了解了 Partial、Readonly 这一类属性修饰的工具类型，不妨想想它们是否能满足我们的需要？假设场景逐渐开始变得复杂，比如以下这些情况：

  -现在的属性修饰是浅层的，如果我想将嵌套在里面的对象类型也进行修饰，需要怎么改进？
  -现在的属性修饰是全量的，如果我只想修饰部分属性呢？这里的部分属性，可能是基于传入已知的键名来确定（比如属性a、b），也可能是基于属性类型来确定(比如所有函数类型的值)？
 */
})()
